#pragma once

#include <functional>
#include <unordered_map>
#include <atomic>

#include <QString>
#include <stdint.h>
#include <QVariant>
#include <mutex>

class Cpu;
class JsFunction
{
private:
    JsFunction(const QString &convertedStr) : convertedStr(convertedStr){}
public:
    ~JsFunction();
    JsFunction(JsFunction &&rhs)
    {
        this->convertedStr = rhs.convertedStr;
        rhs.convertedStr.clear();
    }
public:
    operator QVariant ()
    {
        return convertedStr;
    }
private:
    JsFunction(JsFunction &) = delete;
    JsFunction & operator = (JsFunction &) = delete;
private:
    QString convertedStr;
    friend class JsFunctionManager;
};
class JsFunctionManager
{
public:
    using JsFunctionType = std::function<void(QVariant)>;

private:
    JsFunctionManager();
public:
    ~JsFunctionManager();
public:
    static void init(Cpu *cpu);
    static JsFunction port(JsFunctionType func);
    //static void remove(const QString &funcstr);
    //static void remove(JsFunctionType func);
private:
    static QString mkJsFunctionStr(uint64_t id);
    static uint64_t idFromFunctionStr(const QString str);
private:
    uint64_t _add(JsFunctionType func);
    //void _remove(JsFunctionType func);
    void _remove(uint64_t id);
private:
    void onJsFunctionCalled(QVariantMap args);
private:
    std::atomic<uint64_t> lastId = 0;
    std::mutex locker;
    std::unordered_map<uint64_t, JsFunctionType> functions = std::unordered_map<uint64_t, JsFunctionType>(1024);
private:
    static JsFunctionManager *_instance;
    friend class JsFunction;
};

